package com.cictec.middleware.core.service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.PostConstruct;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.cictec.middleware.commons.cache.ecache.EHCacheUtils;
import com.cictec.middleware.commons.utils.Constants;
import com.cictec.middleware.commons.utils.PMSUtils;
import com.cictec.middleware.commons.utils.PropertiesUtils;
import com.cictec.middleware.commons.utils.ZoneUtils;
import com.cictec.middleware.commons.utils.gps.CoordinateConversion;
import com.cictec.middleware.commons.utils.gps.CoordinateConversion.UTMPoint;
import com.cictec.middleware.commons.utils.gps.GpsUtils;
import com.cictec.middleware.commons.utils.gps.Point;
import com.cictec.middleware.core.entity.BusLineMapPoint;
import com.cictec.middleware.core.entity.BusLineStation;
import com.cictec.middleware.core.mapper.BusLineStationMapper;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.LineSegment;
import com.vividsolutions.jts.geom.LinearRing;
import com.vividsolutions.jts.geom.Polygon;
import com.vividsolutions.jts.operation.buffer.BufferOp;
import com.vividsolutions.jts.operation.buffer.BufferParameters;

/**
 * 线路信息-站点信息service
 * @author ql
 *
 */
@SuppressWarnings({ "rawtypes", "unchecked" })
@Service
public class BusLineStataionService {

	public static Logger logger = LoggerFactory.getLogger(BusLineStataionService.class);


	@Autowired
	private BusLineStationMapper busLineStationMapper;
	@Autowired
	private BusLineMapPointService busLineMapPointService;
//	private MybatisDaoUtil<BusLineStation> lineStationDao = new MybatisDaoUtil<BusLineStation>();
	
	private static String ALL_STATION_GEOMETRY = "bus-line-stations-geometry"; 		// 线路站点的集合图形
	private static String STATION_GEOMETRY = "bus-line-station-geometry"; 		  	// 一个站点的几何图形
	
	private static int STATIOIN_EXTEND = 10;
	private static int STATION_BUFFER = 30;		// 圆形站点缓冲区
	private static int STATION_LR_BUFFER = 50;  // 多边形站点缓冲区

	@PostConstruct
	private void init() {
		STATION_BUFFER = PropertiesUtils.getIntValue("system.params.station.buffer", 30);

	}
	
	/**
	 * 刷新线路站点缓存
	 * 
	 * @param lineUuid
	 * @param lineType
	 */
	public void reloadLineStation(String lineUuid, String lineType) {

		String cacheKey = lineUuid + "-" + (lineType == null ? "" : lineType);
		List<BusLineStation> lss = selectLineStationByLineType(lineUuid, lineType);
		EHCacheUtils.setValue(ALL_STATION_GEOMETRY, cacheKey, lss);

	}
	
	/**
	 * 【缓存】获取线路上所有站点信息
	 * 
	 * @param lineUuid
	 * @param lineType
	 * @return
	 */
	public List<BusLineStation> getLineStationAll(String lineUuid, String lineType) {
		
		String cacheKey = lineUuid + "-" + (lineType == null ? "" : lineType);

		List<BusLineStation> lss = EHCacheUtils.getValue(ALL_STATION_GEOMETRY, cacheKey);

		if (lss != null) {
			return lss;
		}
		
		lss = selectLineStationByLineType(lineUuid, lineType);

		EHCacheUtils.setValue(ALL_STATION_GEOMETRY, cacheKey, lss);

		return lss;
	}
	
	/**
	 * 【缓存】获取线路的第一个站点信息
	 * 
	 * @param lineUuid
	 * @param lineType
	 * @return
	 */
	public BusLineStation getLineStationFirst(String lineUuid, String lineType) {

		List<BusLineStation> stationList = getLineStationAll(lineUuid, lineType);
		if (stationList.size() > 0) {
			return stationList.get(0);
		} else {
			return null;
		}
	}
	

	/**
	 * 【缓存】获取指定线路线路类型最后一个站点信息
	 * 
	 * @param lineUuid
	 * @param lineType
	 * @return
	 */
	public BusLineStation getLineStationLast(String lineUuid, String lineType) {

		List<BusLineStation> stationList = getLineStationAll(lineUuid, lineType);
		if (stationList.size() > 0) {
			return stationList.get(stationList.size() - 1);
		} else {
			return null;
		}
	}
	
	/**
	 * 根据 线路uuid， 上传数据站点编号，查询当前站点（线路上下行）信息
	 * @param lineUuid
	 * @param stationSeq 站点序号
	 * @return
	 */
	public BusLineStation getLineStationByStationSeq(String lineUuid, String lineType, int stationSeq) {
		
		List<BusLineStation> stationList = getLineStationAll(lineUuid, lineType);
		
		BusLineStation station = null;
		for (BusLineStation lineStation : stationList) {
			if (lineStation.getLsSequence() == stationSeq) {
				station = lineStation;
				break;
			}
		}
		return station;
	}

	
	/**
	 * 根据 线路uuid， 上传数据站点编号，查询当前站点（线路上下行）信息
	 * 【注意】这里按照 线路站点 数组 的index值
	 * @param lineUuid
	 * @param stationCode 【上传数据】站点编号
	 * @return
	 */
	public BusLineStation getLineStationByStationSeq(String lineUuid, int stationCode) {
		
		List<BusLineStation> stationList = getLineStationAll(lineUuid, null);
		
		BusLineStation station = null;
		if (stationList.size() == 0 || stationCode > stationList.size()) {
			station = null;
		} else {
			station = stationList.get(stationCode - 1);
		}
		return station;
	}
	
	/**
	 * 【缓存】获取指定线路线路类型站点之后的站点信息
	 * @param lineUuid
	 * @param lineType
	 * @param seq	如果是最后一个站点，返回反向第一个站点
	 * @return
	 */
	public BusLineStation getLineStationNext(String lineUuid, String lineType, int seq) {
		
		
		if(isLastLineStation(lineUuid, lineType, seq)){
			return getLineStationByStationSeq(lineUuid, lineType.equals(Constants.VAL_LINE_UP) ? Constants.VAL_LINE_DOWN : Constants.VAL_LINE_UP, 1);
		}
		
		return getLineStationByStationSeq(lineUuid, lineType, seq + 1);
	}
	
	/**
	 * 获取当前线路第{x}站
	 * @param lineUuid			线路UUID
	 * @param lineType			线路类型
	 * @param stationIndex		是否是第x站, x>0正数第几站, x<0倒数第几站, x=0表示当前站返回ture
	 * @return
	 */
	public BusLineStation getLineStationByIndex(String lineUuid, String lineType, int stationIndex) {
		List<BusLineStation> stationList = getLineStationAll(lineUuid, lineType);

		BusLineStation lineStation = null;
		if (Math.abs(stationIndex) <= stationList.size()) {
			// 判定当前给定站序，是否大于当前线路总的站点数
			if (stationIndex > 0) {
				lineStation = stationList.get(stationIndex - 1);
			} else if (stationIndex < 0) {
				lineStation = stationList.get(stationList.size() + stationIndex);
			}

		}
		return lineStation;
	}
	
	/**
	 * 判定当前站点是否是最后一站
	 * @param lineUuid
	 * @param lineType
	 * @param stationSequence 站点序号
	 * @return
	 */
	public boolean isLastLineStation(String lineUuid, String lineType, int stationSequence){
		
		BusLineStation lineStation = getLineStationLast(lineUuid, lineType); 
		if(lineStation.getLsSequence() == stationSequence){
			return true;
		}
		return false;
	}
	
	
	/**
	 * 判定当前站是否是第{x}站
	 * <br>根据线路类型判定，如果是单向、双向发车，lineType不为null的时候，取指定上下行总的站点排序
	 * @param lineUuid			线路UUID
	 * @param lineType			线路类型
	 * @param stationSequence	当前站站序
	 * @param stationIndex		是否是第x站, x>0整数第几站, x<0倒数第几站, x=0返回false,不做判定
	 * @return
	 */
	public boolean isLineStationByIndex(String lineUuid, String lineType, int stationSequence, int stationIndex) {
		
		BusLineStation ls = getLineStationByIndex(lineUuid, lineType, stationIndex);
		
		return stationSequence == ls.getLsSequence();
	}
	
	/**
	 * 【数据库】【线路类型下所有站点】查询线路站点信息
	 * @param lineUuid
	 * @param lineType 可为null，为null查询线路所有站点
	 * @return
	 */
	public List<BusLineStation> selectLineStationByLineType(String lineUuid, String lineType){
		
		if(PMSUtils.isEmpty(lineType)){
			logger.debug("【BusLineService】位置定线路类型 getLineStationAll(lineUuid {}, lineType {})", lineUuid, lineType);
		}

		
		Map parMap = new HashMap();
		parMap.put("lineUuid", lineUuid);
		parMap.put("lineType", lineType);
		
//		List<BusLineStation> stationList = lineStationDao.selectList("com.cictec.middleware.core.mapper.BusLineStationMapper.selectLineStationByParams", parMap);
		List<BusLineStation> stationList = busLineStationMapper.selectLineStationByParams(parMap);
		for (BusLineStation ls : stationList) {
			// 计算车站的进出站夹角
			_setStationEnterOutAngle(ls);
		}
		return stationList;
	}
	
	/**
	 * 计算车站的进出站夹角
	 * 
	 * @param ls
	 */
	protected void _setStationEnterOutAngle(BusLineStation ls) {

		if (ls == null) {
			return;
		}

		// 车站的进出站夹角计算，计算原理根据地图线路上的连接线段判定。站点前一个地图点到站点的夹角为进站夹角。
		List<BusLineMapPoint> mps = _getStationNearLines(ls);

		for (int i = 0; i < mps.size(); i++) {
			BusLineMapPoint stationPoint = mps.get(i);
			if (stationPoint.getMlStaUuid() != null && stationPoint.getMlWhichstop() == ls.getLsSequence()) {
				// 进站夹角计算
				if (i > 0) {
					// 站点前一个地图坐标点
					BusLineMapPoint ml = mps.get(i - 1);
					// 确定下一个点是站点。
					LineSegment enterLine = new LineSegment(
							new Coordinate(ml.getUtmPoint().getX(), ml.getUtmPoint().getY()),
							new Coordinate(stationPoint.getUtmPoint().getX(), stationPoint.getUtmPoint().getY()));
					ls.setEnterAngle(enterLine.angle());
				}
				// 出站夹角计算
				if (i + 1 < mps.size()) {
					// 站点后的一个地图坐标点。
					BusLineMapPoint ml = mps.get(i + 1);
					LineSegment outLine = new LineSegment(
							new Coordinate(stationPoint.getUtmPoint().getX(), stationPoint.getUtmPoint().getY()),
							new Coordinate(ml.getUtmPoint().getX(), ml.getUtmPoint().getY()));
					ls.setLeaveAngle(outLine.angle());
				}
				break;
			}
		}
	}
	
	/**
	 * 给出一个站点获取站点的前一个地图连线和后一个连线点。 如果非首发站和终点站返回三个地图点。
	 * 
	 * @param ls
	 * @return
	 */
	protected List<BusLineMapPoint> _getStationNearLines(BusLineStation ls) {
		List<BusLineMapPoint> mps = new ArrayList<BusLineMapPoint>();
		List<BusLineMapPoint> mls = busLineMapPointService.getBusLineMapPoint(ls.getLsLineUuid(), ls.getLsLineType());
		for (int i = 0; i < mls.size(); i++) {
			BusLineMapPoint mapPoint = mls.get(i);
//			if (mapPoint.getMlStaUuid() != null && mapPoint.getMlSequence() == ls.getLsSequence()) {
			if (mapPoint.getMlStaUuid() != null && mapPoint.getMlWhichstop() == ls.getLsSequence()) {
				// 进站夹角计算
				if (i > 0) {
					// 站点前一个地图坐标点
					mps.add(mls.get(i - 1));
				}
				mps.add(mls.get(i));
				// 出站夹角计算
				if (i + 1 < mls.size()) {
					// 站点后的一个地图坐标点。
					mps.add(mls.get(i + 1));
				}
				break;
			}
		}
		return mps;
	}
	
	
	
	
	
	/**
	 * 根据位置信息（坐标）获取站点信息
	 * 
	 * @param lineUuid
	 * @param lineType
	 * @param lat
	 * @param lng
	 * @return
	 */
	public List<BusLineStation> getLineStationByPosition(String lineUuid, String lineType, double lat, double lng) {

		List<BusLineStation> result = new ArrayList<BusLineStation>();

		Geometry geoPoint = ZoneUtils.getPointGeometry(lat, lng);
		List<BusLineStation> lss = getLineStationAll(lineUuid, lineType);

		if (lss != null) {
			for (BusLineStation ls : lss) {
				Geometry lsg = getStationGeometry(ls);
				if (lsg != null && lsg.contains(geoPoint)) {
					result.add(ls);
				}
			}
		}

		return result;
	}
	

	
	/**
	 * 获取一个站点的几何图形。
	 * 
	 * @param currentStation
	 * @return
	 */
	protected Geometry getStationGeometry(BusLineStation currentStation) {

//		if(PMSUtils.isEmpty(currentStation.getLsStaEnterLat()) 
//				|| PMSUtils.isEmpty(currentStation.getLsStaEnterLng())
//				|| PMSUtils.isEmpty(currentStation.getLsStaOutLat())
//				|| PMSUtils.isEmpty(currentStation.getLsStaOutLng())){
//			logger.debug("站点信息未标准 进、出站经纬度");
//			return null;
//		}
		
		
		String cacheKey = currentStation.getLsUuid();
		Geometry stationBuffer = EHCacheUtils.getValue(STATION_GEOMETRY, cacheKey);

		if (stationBuffer != null) {
			return stationBuffer;
		}

		String enterLat = GpsUtils.convertLatitude(PMSUtils.isNull(currentStation.getLsStaEnterLat()));
		String enterLng = GpsUtils.convertLongitude(PMSUtils.isNull(currentStation.getLsStaEnterLng()));

		String outLat = GpsUtils.convertLatitude(PMSUtils.isNull(currentStation.getLsStaOutLat()));
		String outLng = GpsUtils.convertLongitude(PMSUtils.isNull(currentStation.getLsStaOutLng()));

		if (!enterLat.equals(outLat) || !enterLng.equals(outLng)) {
			// 站点坐标为两个坐标情况
			Point enterPoint = GpsUtils.diqiuToHuoxing(enterLat, enterLng);
			UTMPoint enterUTM = CoordinateConversion.latLon2UTM(enterPoint.getY(), enterPoint.getX());

			Point outPoint = GpsUtils.diqiuToHuoxing(outLat, outLng);
			UTMPoint outUTM = CoordinateConversion.latLon2UTM(outPoint.getY(), outPoint.getX());

			Coordinate[] cs = new Coordinate[2];
			cs[0] = new Coordinate(enterUTM.getX(), enterUTM.getY());
			cs[1] = new Coordinate(outUTM.getX(), outUTM.getY());

			LineSegment ls = new LineSegment(cs[0], cs[1]);
			double dis = ls.getLength();
			double f = STATIOIN_EXTEND / dis;
			cs[0] = ls.pointAlong(-f);
			cs[1] = ls.pointAlong(1 + f);

			Geometry gline = new GeometryFactory().createLineString(cs);
			BufferOp pyBufferOp = new BufferOp(gline);
			pyBufferOp.setEndCapStyle(BufferParameters.CAP_FLAT);

			stationBuffer = pyBufferOp.getResultGeometry(STATION_BUFFER);

		} else {
			// 站点坐标为一个情况.
			// stationBuffer = getStationRectBuffer(currentStation);
			stationBuffer = getStationCircleBuffer(currentStation);

		}

		EHCacheUtils.setValue(STATION_GEOMETRY, cacheKey, stationBuffer);

		return stationBuffer;
	}
	
	/**
	 * 获取站点（一个坐标情况下）的圆形的缓冲区
	 * 
	 * @param currentStation
	 * @return
	 */
	protected Geometry getStationCircleBuffer(BusLineStation currentStation) {
		// 中间件内部统一使用火星坐标系
//		Point enterPoint = GpsUtils.diqiuToHuoxing(
//				GpsUtils.convertLatitude(PMSUtils.isNull(currentStation.getLsStaLat())),
//				GpsUtils.convertLongitude(PMSUtils.isNull(currentStation.getLsStaLng())));
//		Point enterPoint = new Point(Double.valueOf(currentStation.getLsStaLng()),Double.valueOf(currentStation.getLsStaLat()));
//		UTMPoint enterUTM = CoordinateConversion.latLon2UTM(enterPoint.getY(), enterPoint.getX());
//		System.out.println(JSON.toJSONString(enterUTM));
		UTMPoint enterUTM = CoordinateConversion.latLon2UTM(Double.valueOf(currentStation.getLsStaLat()), Double.valueOf(currentStation.getLsStaLng()));
//		System.out.println(JSON.toJSONString(enterUTM));
		
		
		Geometry stationBuffer = createCircle(enterUTM.getX(), enterUTM.getY(), STATION_BUFFER);
		return stationBuffer;
	}
	
	/**
	 * 获取站点（一个坐标情况下）的矩形的缓冲区。
	 * 
	 * @param lineStation
	 * @return
	 */
	protected Geometry getStationRectBuffer(BusLineStation lineStation) {
		Geometry stationBuffer;
		List<BusLineMapPoint> mapPoints = _getStationNearLines(lineStation);
		List<Coordinate> csList = new ArrayList<Coordinate>();

		for (int i = 0; i < mapPoints.size(); i++) {
			BusLineMapPoint stationPoint = mapPoints.get(i);
			if (stationPoint.getMlWhichstop() == lineStation.getLsSequence()) {
				Coordinate stationCoordinate = new Coordinate(stationPoint.getUtmPoint().getX(),
						stationPoint.getUtmPoint().getY());
				// 进站夹角计算
				if (i > 0) {
					// 站点前一个地图坐标点
					BusLineMapPoint ml = mapPoints.get(i - 1);
					// 确定下一个点是站点。
					LineSegment enterLine = new LineSegment(stationCoordinate, new Coordinate(ml.getUtmPoint().getX(), ml.getUtmPoint().getY()));
					csList.add(enterLine.pointAlong(STATION_BUFFER / enterLine.getLength()));
				}
				csList.add(stationCoordinate);
				// 出站夹角计算
				if (i + 1 < mapPoints.size()) {
					// 站点后的一个地图坐标点。
					BusLineMapPoint ml = mapPoints.get(i + 1);
					LineSegment outLine = new LineSegment(stationCoordinate, new Coordinate(ml.getUtmPoint().getX(), ml.getUtmPoint().getY()));
					csList.add(outLine.pointAlong(STATION_BUFFER / outLine.getLength()));

				}
				break;
			}
		}
		Coordinate[] csArray = new Coordinate[csList.size()];
		for (int i = 0; i < csList.size(); i++) {
			csArray[i] = csList.get(i);
		}
		Geometry gline = new GeometryFactory().createLineString(csArray);
		BufferOp pyBufferOp = new BufferOp(gline);
		pyBufferOp.setEndCapStyle(BufferParameters.CAP_FLAT);

		stationBuffer = pyBufferOp.getResultGeometry(STATION_LR_BUFFER);
		return stationBuffer;
	}
	
	public static Polygon createCircle(double x, double y, final double radius) {
		final int SIDES = 32;// 圆上面的点个数
		Coordinate coords[] = new Coordinate[SIDES + 1];
		for (int i = 0; i < SIDES; i++) {
			double angle = ((double) i / (double) SIDES) * Math.PI * 2.0;
			double dx = Math.cos(angle) * radius;
			double dy = Math.sin(angle) * radius;
			coords[i] = new Coordinate((double) x + dx, (double) y + dy);
		}
		coords[SIDES] = coords[0];
		GeometryFactory geometryFactory = new GeometryFactory();
		LinearRing ring = geometryFactory.createLinearRing(coords);
		Polygon polygon = geometryFactory.createPolygon(ring, null);
		return polygon;
	}
	
	
	
	
	
}
